﻿using Kaskelot.SP.Model.Client;
using Kaskelot.SP.Model.Contracts;
using Kaskelot.SP.Services.Client.Mapping;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Stockholm.SOA.Kaskelot.WCF.DataContracts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web;
using Aspose.Words;
using System.Text;
using System.Xml;
using Kaskelot.SP.Core;

namespace Kaskelot.SP.Services.Client
{
    [ServiceContract(Namespace = "http://Kaskelot.SP.Services")]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ClientDocumentService
    {
        [OperationContract]
        [WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<IEnumerable<ClientDokument>> GetTemplates()
        {
            ClientServiceResult<IEnumerable<ClientDokument>> csr = new ClientServiceResult<IEnumerable<ClientDokument>>();

            try
            {
                DocumentService svc = new DocumentService();
                csr.Data = svc.GetTemplates(SPContext.Current.Site).Select(d => d.ToClientContract()).ToList();
            }
            catch (Exception ex)
            {
                csr.ErrorMessage = ex.Message;
                csr.HasError = true;
            }

            return csr;
        }

        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> DeleteTemplate(string dokumentId)
        {
            ClientServiceResult<string> csr = new ClientServiceResult<string>();

            try
            {
                if (!ApplicationContext.Current.Val.Aktivt)
                    throw new ApplicationException("Valet är låst och kan inte redigeras.");

                int dokId = 0;
                if (int.TryParse(dokumentId, out dokId))
                {
                    DocumentService docSvc = new DocumentService();
                    docSvc.DeleteTemplate(SPContext.Current.Site, dokId);
                }
            }
            catch (Exception ex)
            {
                csr.ErrorMessage = ex.Message;
                csr.HasError = true;
            }

            return csr;
        }

        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> RenderPersonDocument(string TemplateId, string IdList)
        {
            #region Init
            ClientServiceResult<string> csr = new ClientServiceResult<string>();
            DocumentService svc = new DocumentService();

            License license = new License();
            license.SetLicense("Aspose.Words.lic");

            string filename = SPContext.Current.Web.CurrentUser.ID + ".pdf";
            #endregion

            try
            {
                DeleteTempFile(filename);

                SPFile template = LoadTemplate(int.Parse(TemplateId));

                #region Hämta personerna
                IEnumerable<string> idList = IdList.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                IEnumerable<PersonFull> personer = null;
                using (PersonService pSvc = new PersonService())
                {
                    personer = pSvc.GetPersonList(idList.Select(id => new Guid(id.Trim())));
                }

                if (personer == null || personer.ToArray().Length <= 0)
                    throw new ApplicationException("Inga personer valda");

                personer = personer.OrderBy(x => x.Fornamn).ThenBy(x => x.Efternamn);
                #endregion

                #region Merge
                Aspose.Words.Document document = null;

                foreach (PersonFull p in personer)
                {
                    Aspose.Words.Document page = new Aspose.Words.Document(template.OpenBinaryStream());

                    page.MailMerge.CleanupOptions =
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveUnusedRegions |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveUnusedFields |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveEmptyParagraphs |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveContainingFields;

                    page.MailMerge.ExecuteWithRegions(new IEnumerableMailMergeDataSource(new PersonFull[] { p }, "PersonFull"));

                    if (document == null)
                        document = page;
                    else
                        document.AppendDocument(page, ImportFormatMode.UseDestinationStyles);
                }
                #endregion

                csr.Data = SaveDocument(document, filename);
            }
            catch (Exception e)
            {
                csr.ErrorMessage = e.Message;
                csr.HasError = true;
            }

            return csr;
        }

        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> RenderByggnadDocument(string TemplateId, string IdList)
        {
            #region Init
            ClientServiceResult<string> csr = new ClientServiceResult<string>();
            DocumentService svc = new DocumentService();

            License license = new License();
            license.SetLicense("Aspose.Words.lic");

            string filename = SPContext.Current.Web.CurrentUser.ID + ".pdf";
            #endregion

            try
            {
                DeleteTempFile(filename);

                SPFile template = LoadTemplate(int.Parse(TemplateId));

                #region Hämta byggnaderna
                IEnumerable<string> idList = IdList.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                IEnumerable<ByggnadFull> byggnader = null;
                using (ByggnadService bSvc = new ByggnadService())
                {
                    byggnader = bSvc.GetByggnadList(idList.Select(id => new Guid(id.Trim())));
                }

                if (byggnader == null || byggnader.ToArray().Length <= 0)
                    throw new ApplicationException("Inga byggnader valda");

                byggnader = byggnader.OrderBy(x => x.Namn);
                #endregion

                #region Merge
                Aspose.Words.Document document = null;

                foreach (ByggnadFull b in byggnader)
                {
                    Aspose.Words.Document page = new Aspose.Words.Document(template.OpenBinaryStream());

                    page.MailMerge.CleanupOptions =
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveUnusedRegions |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveUnusedFields |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveEmptyParagraphs |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveContainingFields;

                    page.MailMerge.ExecuteWithRegions(new IEnumerableMailMergeDataSource(new ByggnadFull[] { b }, "ByggnadFull"));

                    if (document == null)
                        document = page;
                    else
                        document.AppendDocument(page, ImportFormatMode.KeepSourceFormatting);
                }
                #endregion

                csr.Data = SaveDocument(document, filename);
            }
            catch (Exception e)
            {
                csr.ErrorMessage = e.Message;
                csr.HasError = true;
            }

            return csr;
        }

        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> RenderValdistriktDocument(string TemplateId, string IdList)
        {
            #region Init
            ClientServiceResult<string> csr = new ClientServiceResult<string>();
            DocumentService svc = new DocumentService();

            License license = new License();
            license.SetLicense("Aspose.Words.lic");

            string filename = SPContext.Current.Web.CurrentUser.ID + ".pdf";
            #endregion

            try
            {
                DeleteTempFile(filename);

                SPFile template = LoadTemplate(int.Parse(TemplateId));

                #region Hämta valdistrikten
                IEnumerable<string> idList = IdList.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                IEnumerable<ValdistriktFull> valdistrikt = null;
                using (BemanningService bSvc = new BemanningService())
                {
                    valdistrikt = bSvc.GetValdistriktFull(idList.Select(id => new Guid(id.Trim())));
                }

                if (valdistrikt == null || valdistrikt.ToArray().Length <= 0)
                    throw new ApplicationException("Inga valdistrikt valda");

                valdistrikt = valdistrikt.OrderBy(vd => vd.FullName);
                #endregion

                #region Merge
                Aspose.Words.Document document = null;

                foreach (Valdistrikt b in valdistrikt)
                {
                    Aspose.Words.Document page = new Aspose.Words.Document(template.OpenBinaryStream());

                    page.MailMerge.CleanupOptions =
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveUnusedRegions |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveUnusedFields |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveEmptyParagraphs |
                        Aspose.Words.Reporting.MailMergeCleanupOptions.RemoveContainingFields;

                    page.MailMerge.ExecuteWithRegions(new IEnumerableMailMergeDataSource(new Valdistrikt[] { b }, "Valdistrikt"));

                    if (document == null)
                        document = page;
                    else
                        document.AppendDocument(page, ImportFormatMode.KeepSourceFormatting);
                }
                #endregion

                csr.Data = SaveDocument(document, filename);
            }
            catch (Exception e)
            {
                csr.ErrorMessage = e.Message;
                csr.HasError = true;
            }

            return csr;
        }

        private void DeleteTempFile(string filename)
        {
            Guid siteId = SPContext.Current.Site.ID;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(siteId))
                {
					//bool oldFormDigestSetting = site.WebApplication.FormDigestSettings.Enabled;
                    bool oldAllowUnsafeUpdates = site.RootWeb.AllowUnsafeUpdates;
                    try
                    {
						//site.WebApplication.FormDigestSettings.Enabled = false;
                        site.RootWeb.AllowUnsafeUpdates = true;

                        DocumentService svc = new DocumentService();
                        IEnumerable<Kaskelot.SP.Model.Contracts.Document> docs = svc.GetTempDocs(site);
                        Kaskelot.SP.Model.Contracts.Document doc = docs.Where(d => d.FileName == filename).FirstOrDefault();
                        if (doc != null)
                        {
                            svc.DeleteTempDoc(site, doc.Id);
                        }
                    }
                    finally
                    {
						//site.WebApplication.FormDigestSettings.Enabled = oldFormDigestSetting;
                        site.RootWeb.AllowUnsafeUpdates = oldAllowUnsafeUpdates;
                    }
                }
            });
        }

        private SPFile LoadTemplate(int templateId)
        {
            DocumentService svc = new DocumentService();

            SPFile template = null;
            try
            {
                template = svc.GetTemplateFolder(SPContext.Current.Site).Files.Cast<SPFile>().Where(x => x.Item.ID == templateId).FirstOrDefault();
            }
            catch { }

            if (template == null || !template.Exists)
                throw new ApplicationException("Mallen kunde inte hittas.");

            return template;
        }

        private string SaveDocument(Aspose.Words.Document document, string filename, SaveFormat format = SaveFormat.Pdf)
        {
            DocumentService svc = new DocumentService();
            Guid siteId = SPContext.Current.Site.ID;
            string fileUrl = string.Empty;
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(siteId))
                {
                    bool allowUnsafe = site.RootWeb.AllowUnsafeUpdates;
					//bool formDigestSettings = site.WebApplication.FormDigestSettings.Enabled;

                    try
                    {
                        site.RootWeb.AllowUnsafeUpdates = true;
						//site.WebApplication.FormDigestSettings.Enabled = false;

                        using (MemoryStream fs = new MemoryStream())
                        {
                            document.Save(fs, format);

                            var oldContext = HttpContext.Current;
                            SPFile file = null;
                            try
                            {
                                HttpContext.Current = null;
                                SPFolder folder = svc.GetTempFolder(site);
                                file = folder.Files.Add(filename, fs, true);
                            }
                            finally
                            {
                                HttpContext.Current = oldContext;
                            }

                            fileUrl = file.Url;
                        }
                    }
                    finally
                    {
                        site.RootWeb.AllowUnsafeUpdates = allowUnsafe;
						//site.WebApplication.FormDigestSettings.Enabled = formDigestSettings;
                    }                    
                }
            });

            return fileUrl;
        }

        [OperationContract]
        [WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> CreateLISAPersonFil()
        {
            ClientServiceResult<string> csr = new ClientServiceResult<string>();

            try
            {
                IntegrationService svc = new IntegrationService();
                csr.Data = svc.CreateLISAFiler();
            }
            catch (Exception ex)
            {
                csr.ErrorMessage = ex.Message;
                csr.HasError = true;
            }

            return csr;
        }

        [OperationContract]
        [WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> CreateSkatteverketFil()
        {
            ClientServiceResult<string> csr = new ClientServiceResult<string>();

            try
            {
                IntegrationService svc = new IntegrationService();
                csr.Data = svc.CreateSkatteverketFiler();
            }
            catch (Exception ex)
            {
                csr.ErrorMessage = ex.Message;
                csr.HasError = true;
            }

            return csr;
        }

        [OperationContract]
        [WebGet(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
        public ClientServiceResult<string> CreateArkivFil(string valtyp)
        {
            ClientServiceResult<string> csr = new ClientServiceResult<string>();

            try
            {
                IntegrationService svc = new IntegrationService();
                csr.Data = svc.CreateArkiv(valtyp);
            }
            catch (Exception ex)
            {
                csr.ErrorMessage = ex.Message;
                csr.HasError = true;
            }

            return csr;
        }
    }
}
